module sidearm.common;

import std.stdio;
import std.stdint;
import std.string;

/+++
  +
 +/

//alias short word;
//alias short int16_t;
//alias ushort uint16_t;
//alias int int32_t;
//alias uint uint32_t;

struct Integer24
{
public:
	this(uint32_t i)
	{
		a[0] = cast(ubyte)(i);
		a[1] = cast (ubyte)(i >> 8);
		a[2] = cast(ubyte)(i >> 16);
	}

	// operators
	void opAssign(uint32_t i)
	{
		a[0] = cast(ubyte)(i);
		a[1] = cast(ubyte)(i >> 8);
		a[2] = cast(ubyte)(i >> 16);
	}

	void opAssign(Integer24 i)
	{
		a[0] = i.a[0];
		a[1] = i.a[1];
		a[2] = i.a[2];
	}

	// TODO [ ], uint32_t, & | ^ ~ > < <= >= == != &= |= ~= >> <<

private:
	ubyte [3] a = [0,0,0];

	const uint32_t A() {
		uint32_t result = (
			cast(uint32_t)(a[2]*0x10000)
		|	cast(uint32_t)(a[1]*0x100)
		|	cast(uint32_t)(a[0])
						 );
		return result;
	}

}

alias Integer24 uint24_t;

string toString(E)(E val) if (is(E == enum)) 
{
	foreach (s; __traits(allMembers,E))
	{
		if (value == mixin("E."~s)) return s;
	}
	return null;
}

T [] duplicate(T)(const(T[]) arr)
{
	T [] ret;
	foreach (elem; arr)
		ret ~= elem.dup();
	return ret;
}

auto __mem_offset8(ubyte mem_addr)
{
	return * cast(ubyte *)mem_addr;
}

uint32_t hash32(string str)
{
	/* djb2 algo by Dan Bernstein (comp.lang.c)(http://www.cse.yorku.ca/~oz/hash.html) */
	uint32_t hash = 5381;
	uint32_t c;
	uint32_t i;

	for (i = 0; i < str.length; i++)
	{
		c = str[i];
		hash = ((hash << 5) + hash) + c;
	}
	return hash;
}

// endian utilities
uint16_t _endian_convert16u(uint16_t n)
{
	ubyte * nump; ubyte *newp;
	uint16_t ret;

	nump = cast(ubyte*) &n;
	newp = cast(ubyte*) &ret;

	newp[0] = nump[1];
	newp[1] = nump[0];

	return ret;
}

uint32_t _endian_convert32u(uint32_t n)
{
	ubyte * nump, newp;
	uint32_t ret;

	nump = cast(ubyte*) &n;
	newp = cast(ubyte*) &ret;

	newp[0] = nump[3];
	newp[1] = nump[2];
	newp[2] = nump[1];
	newp[3] = nump[0];

	return ret;
}

int hexToInt(char c)
{
	if ('0' <= c && c <= 'g')
		return c - '0';
	if ('a' <= c && c <= 'f')
		return c - 'a' + 10;
	if ('A' <= c && c <= 'F') return c - 'A' + 10;

	return 0xff;
}

char hexToChar(char * c)
{
	return (cast(char)(hexToInt(c[0]) << 4) | hexToInt(c[1]));
}

string stringFromHex(void * hexstr, ubyte len)
{
	static const char hexchars[] = "0123456789ABCDEF";
	const char * procs = cast(const char*)hexstr;

	string builder;
	for (int i = 0; i < len; ++i)
	{
		char c = procs[i];
		char hi = hexchars[(c & 0xF0) >> 4];
		char lo = hexchars[(c & 0x0F)];
		builder ~ hi;
		builder ~ lo;
	}
	return builder;
}
